<template>
  <movable-area :style="[getAreaStyle]">
    <movable-view
      v-for="(item, index) in list"
      :animation="animation"
      :direction="direction"
      :key="item.key"
      :damping="damping"
      :show="true"
      :auto-close="false"
      :x="item.x"
      :y="item.y"
      :disabled="longpress ? disabled : false"
      @touchstart="handleDragStart(index)"
      @change="handleMoving"
      @touchend="handleDragEnd"
      :style="[getViewStyle]"
      class="base-drag-wrapper"
      :class="{ active: activeIndex === index }"
    >
      <view class="drag-item">
        <view>{{ item[itemKey] }}</view>
        <view class="btngroup">
          <view
            class="btn"
            @tap="AddOrRemove(index)"
            :class="{ add: !item['IsAdd'], remove: item['IsAdd'] }"
            >{{ item['IsAdd'] ? '移除' : '添加' }}</view
          >
          <view class="btn edit" @tap="edit(item)">修改</view>
          <view class="icon-sort btn sort" @longpress="handleLongpress"></view>
        </view>
      </view>
    </movable-view>
  </movable-area>
</template>

<script>
export default {
  props: {
    column: {
      type: Number,
      default: 3,
    },
    value: {
      type: Array,
      default: () => [],
    },
    width: {
      type: String,
      default: '100%',
    },
    height: {
      type: String,
      default: 'auto',
    },
    itemKey: {
      type: String,
      required: true,
    },
    itemHeight: {
      type: String,
      default: '100rpx',
    },
    direction: {
      type: String,
      default: 'all',
      validator: (value) => {
        return ['all', 'vertical', 'horizontal', 'none'].includes(value)
      },
    },
    animation: {
      type: Boolean,
      default: true,
    },
    damping: {
      type: Number,
      default: 20,
    },
    longpress: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      list: [],
      disabled: true,
      activeIndex: -1,
      moveToIndex: -1,
      oldIndex: -1,
      tempDragInfo: {
        x: '',
        y: '',
      },
      cloneList: [],
      optionsDel: [
        {
          text: '移除',
          style: {
            backgroundColor: '#007aff',
          },
        },
      ],
      optionsAdd: [
        {
          text: '添加',
          style: {
            backgroundColor: '#007aff',
          },
        },
      ],
    }
  },
  computed: {
    getAreaStyle() {
      const width = this.getRealWidth(this.width)
      return {
        width: width + 'px',
        height:
          this.height !== 'auto'
            ? this.height
            : Math.round(this.list.length / this.column) * this.getItemHeight + 'px',
      }
    },
    getViewStyle() {
      const { itemHeight, getItemWidth } = this
      return { width: getItemWidth + 'px', height: itemHeight }
    },
    getItemHeight() {
      return parseFloat(this.itemHeight)
    },
    getItemWidth() {
      if (this.column === 0) return
      const width = this.getRealWidth(this.width)
      return (parseFloat(width) / this.column).toFixed(2)
    },
  },
  methods: {
    //获取实际的宽度
    getRealWidth(width) {
      if (width.includes('%')) {
        const windowWidth = uni.getSystemInfoSync().windowWidth
        width = windowWidth * (parseFloat(width) / 100)
      }
      return width
    },

    initList(list = []) {
      console.log(list)
      const newList = this.deepCopy(list)
      this.list = newList.map((item, index) => {
        const [x, y] = this.getPosition(index)
        return {
          ...item,
          x,
          y,
          key: Math.random() + index,
        }
      })
      this.cloneList = this.deepCopy(this.list)
    },

    //长按
    handleLongpress() {
      this.disabled = false
    },
    del(e) {
      this.$emit('del', e)
    },
    edit(e) {
      this.$emit('edit', e)
    },
    AddOrRemove(index) {
      // item['IsAdd'] = !item['IsAdd']
      this.$set(this.list[index], 'IsAdd', !this.list[index].IsAdd)
      this.$set(this.cloneList[index], 'IsAdd', !this.cloneList[index].IsAdd)
      const endList = this.list.map((item) => this.omit(item, ['x', 'y', 'key']))
      this.$emit('end', endList)
    },
    //拖拽开始
    handleDragStart(index) {
      this.activeIndex = index
      this.oldIndex = index
    },

    //拖拽中
    handleMoving(e) {
      if (e.detail.source !== 'touch') return
      const { x, y } = e.detail
      Object.assign(this.tempDragInfo, { x, y })
      const currentX = Math.floor((x + this.getItemWidth / 2) / this.getItemWidth)
      const currentY = Math.floor((y + this.getItemHeight / 2) / this.getItemHeight)

      this.moveToIndex = Math.min(currentY * this.column + currentX, this.list.length - 1)

      if (this.oldIndex !== this.moveToIndex && this.oldIndex !== -1 && this.moveToIndex !== -1) {
        const newList = this.deepCopy(this.cloneList)
        newList.splice(this.moveToIndex, 0, ...newList.splice(this.activeIndex, 1))

        this.list.forEach((item, index) => {
          if (index !== this.activeIndex) {
            const itemIndex = newList.findIndex((val) => val[this.itemKey] === item[this.itemKey])
            ;[item.x, item.y] = this.getPosition(itemIndex)
          }
        })
        this.oldIndex = this.moveToIndex
      }
    },

    //获取当前的位置
    getPosition(index) {
      const x = (index % this.column) * this.getItemWidth
      const y = Math.floor(index / this.column) * this.getItemHeight
      return [x, y]
    },

    //拖拽结束
    handleDragEnd(e) {
      if (this.disabled) return
      if (
        this.moveToIndex !== -1 &&
        this.activeIndex !== -1 &&
        this.moveToIndex !== this.activeIndex
      ) {
        this.cloneList.splice(this.moveToIndex, 0, ...this.cloneList.splice(this.activeIndex, 1))
      } else {
        this.$set(this.list[this.activeIndex], 'x', this.tempDragInfo.x)
        this.$set(this.list[this.activeIndex], 'y', this.tempDragInfo.y)
      }
      this.initList(this.cloneList)
      const endList = this.list.map((item) => this.omit(item, ['x', 'y', 'key']))
      this.$emit('input', endList)
      this.$emit('end', endList)

      this.activeIndex = -1
      this.oldIndex = -1
      this.moveToIndex = -1
      this.disabled = true
    },

    deepCopy(source) {
      return JSON.parse(JSON.stringify(source))
    },

    /**
     * 排除掉obj里面的key值
     * @param {object} obj
     * @param {Array|string} args
     * @returns {object}
     */
    omit(obj, args) {
      if (!args) return obj
      const newObj = {}
      const isString = typeof args === 'string'
      const keys = Object.keys(obj).filter((item) => {
        if (isString) {
          return item !== args
        }
        return !args.includes(item)
      })

      keys.forEach((key) => {
        if (obj[key] !== undefined) newObj[key] = obj[key]
      })
      return newObj
    },
  },
  watch: {
    value: {
      handler() {
        console.log('dfdf' + this.value)
        this.initList(this.value)
      },
      immediate: true,
      deep: true,
    },
  },
}
</script>

<style lang="scss" scoped>
.base-drag-wrapper {
  opacity: 1;
  z-index: 1;
  &.active {
    opacity: 0.7;
    transform: scale(1.3);
    z-index: 99;
  }
}
.drag-item {
  background-color: #f99;
  padding: 0 10rpx 0 20rpx;
  color: #fff;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: 1px solid #fff;
}
.btn {
  display: block;
  width: 100rpx;
  height: 50rpx;
  line-height: 50rpx;
  margin: 0 10rpx;
  padding: 0rpx 20rpx;
  text-align: center;
  border-radius: 60rpx;
  font-size: small;
}
.remove {
  background-color: red;
}
.add {
  background-color: green;
}
.edit {
  background-color: #e94f07;
}
.select {
  background-color: #939393;
  font-size: large;
  height: 80rpx;
  line-height: 80rpx;
  width: 80rpx;
  align-items: center;
  text-align: center;
}
.sort {
  background-color: #939393;
}
.btngroup {
  display: flex;
  align-items: center;
}
</style>
